package com.xnx.bincker.leader.domain;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.xnx.bincker.leader.core.domain.BasicEntity;
import lombok.Data;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestMethod;

import javax.persistence.*;
import java.io.IOException;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 权限
 */
@Entity
@Data
public class Authority extends BasicEntity {
    private static final long serialVersionUID = 6613092747266437556L;
    @Id
    private String id;
	/**
	 * 权限的ant匹配地址
	 */
	@Column(nullable = false)
	private String mappingInfo;

	/**
	 * 注释描述
	 */
	private String remark;

	/**
	 * 拥有该权限的角色
	 */
	@JsonIgnore
	@ManyToMany(mappedBy = "authorities", fetch = FetchType.EAGER)
	private Set<Role> roles;

	/**
	 * 父级菜单
	 * 用于对权限的分组分类
	 */
	@ManyToOne(cascade = CascadeType.MERGE)
	private Menu parentMenu;

	/**
	 * 该权限所指向的菜单
	 */
	@JsonIgnore
	@OneToOne(mappedBy = "authority", fetch = FetchType.LAZY)
	private Menu menu;

	@JsonIgnore
	public MappingInfo getMappingInfo(){
        ObjectMapper mapper = new ObjectMapper();
        try {
            return mapper.readValue(mappingInfo, MappingInfo.class);
        } catch (IOException e) {
            throw new RuntimeException("权限匹配信息为空", e);
        }
    }

    public void setMappingInfo(MappingInfo mappingInfo){
	    ObjectMapper mapper = new ObjectMapper();
        try {
            this.mappingInfo = mapper.writeValueAsString(mappingInfo);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        if (!super.equals(o)) return false;
        Authority authority = (Authority) o;
        if(authority.parentMenu != parentMenu){
            if(authority.parentMenu == null || parentMenu == null) return false;
            if(!authority.parentMenu.getId().equals(parentMenu.getId())) return false;
        }
        return Objects.equals(id, authority.id) &&
                Objects.equals(mappingInfo, authority.mappingInfo) &&
                Objects.equals(remark, authority.remark);
    }

    @Override
    public int hashCode() {
        return Objects.hash(super.hashCode(), id, mappingInfo, remark, parentMenu==null?"":parentMenu.getId());
    }

    /**
     * 匹配规则
     */
    @Data
    public static class MappingInfo{
        private static final long serialVersionUID = 711821482867894316L;
        /**
         * 匹配路径
         */
        private Set<String> path;
        /**
         * 请求方法
         */
        private Set<RequestMethod> method;
        /**
         * 请求数据类型
         */
        private Set<String> produces;

        public MappingInfo(Set<String> path, Set<RequestMethod> method, Set<MediaType> produces) {
            this.path = path;
            this.method = method;
            this.produces = produces.stream().map(mediaType -> mediaType.getType() + "/" + mediaType.getSubtype()).collect(Collectors.toCollection(HashSet::new));
        }

    }
}
